package main

import (
	"archive/tar"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

const (
	repoAPI = "https://api.github.com/repos/nushell/nushell/releases/latest"
)

func main() {
	// 1. 读取目标目录
	var targetDir string
	fmt.Print("请输入要安装 nushell 的目录（绝对/相对路径均可）：")
	if _, err := fmt.Scanln(&targetDir); err != nil {
		exitErr("读取输入失败", err)
	}
	targetDir, err := filepath.Abs(targetDir)
	if err != nil {
		exitErr("解析路径失败", err)
	}
	if err := os.MkdirAll(targetDir, 0755); err != nil {
		exitErr("创建目录失败", err)
	}
	fmt.Println("目标目录:", targetDir)

	// 2. 获取最新 release 下载地址
	tarURL := getMuslTarURL()
	fmt.Println("获取到下载地址:", tarURL)

	// 3. 下载
	tarPath := filepath.Join(targetDir, "nushell.tar.gz")
	if err := downloadFile(tarPath, tarURL); err != nil {
		exitErr("下载失败", err)
	}
	fmt.Println("下载完成:", tarPath)

	// 4. 解压
	if err := extractTarGz(tarPath, targetDir); err != nil {
		exitErr("解压失败", err)
	}
	// 解压完可把压缩包删掉（可选）
	_ = os.Remove(tarPath)

	// 5. 写入最小 config.nu 模板
	configPath := filepath.Join(targetDir, "config.nu")
	if err := genEmptyConfig(configPath); err != nil {
		exitErr("写入 config.nu 失败", err)
	}
	fmt.Println("安装完成！")
	fmt.Printf("nu 主程序路径: %s\n", filepath.Join(targetDir, "nu"))
	fmt.Printf("config.nu 路径: %s  （可后续自行编辑）\n", configPath)
}

// 请求 GitHub API 找到 linux-x86_64-musl.tar.gz 的 browser_download_url
func getMuslTarURL() string {
	resp, err := http.Get(repoAPI)
	if err != nil {
		exitErr("请求 GitHub API 失败", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		exitErr("GitHub API 返回非 200", nil)
	}
	var rel struct {
		Assets []struct {
			Name               string `json:"name"`
			BrowserDownloadURL string `json:"browser_download_url"`
		} `json:"assets"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&rel); err != nil {
		exitErr("解析 GitHub API 返回体失败", err)
	}
	for _, a := range rel.Assets {
		if strings.Contains(a.Name, "x86_64") &&
			strings.Contains(a.Name, "musl") &&
			strings.HasSuffix(a.Name, ".tar.gz") {
			return a.BrowserDownloadURL
		}
	}
	exitErr("未找到 linux-x86_64-musl 版本", nil)
	return ""
}

// 简单下载
func downloadFile(dst, url string) error {
	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("status %d", resp.StatusCode)
	}
	_, err = io.Copy(out, resp.Body)
	return err
}

// 解压 tar.gz，把 nu 与 nu_plugin_* 拷贝到 targetDir
func extractTarGz(tarPath, targetDir string) error {
	f, err := os.Open(tarPath)
	if err != nil {
		return err
	}
	defer f.Close()
	gzr, err := gzip.NewReader(f)
	if err != nil {
		return err
	}
	defer gzr.Close()
	tr := tar.NewReader(gzr)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		// 只提取我们需要的文件
		base := filepath.Base(hdr.Name)
		if !(base == "nu" || strings.HasPrefix(base, "nu_plugin_")) {
			continue
		}
		dstPath := filepath.Join(targetDir, base)
		if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil {
			return err
		}
		out, err := os.OpenFile(dstPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0755)
		if err != nil {
			return err
		}
		if _, err := io.Copy(out, tr); err != nil {
			out.Close()
			return err
		}
		out.Close()
	}
	return nil
}

// 生成一份空模板，仅给出注释，方便后续手动改
func genEmptyConfig(path string) error {
	tmpl := `# Nushell config.nu 模板
# 此处可写自定义配置，例如：
#
# let $config = {
#   show_banner: false
#   edit_mode: emacs
#   max_history_size: 10000
# }
#
# 保存后重启 nu 即可生效。
`
	return os.WriteFile(path, []byte(tmpl), 0644)
}

func exitErr(msg string, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s: %v\n", msg, err)
	} else {
		fmt.Fprintln(os.Stderr, msg)
	}
	os.Exit(1)
}
